/*
 * Run.java
 * 
 * This file is part of Netuno Proteu.
 * 
 * CajuScript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3, or (at your option) 
 * any later version.
 * 
 * CajuScript is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with CajuScript.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.netuno.proteu;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import org.apache.log4j.Logger;
import org.netuno.psamata.script.ScriptRunner;

/**
 * Run Java and Script files
 * @author eduveks
 */
public class Run {
    static Logger logger = Logger.getLogger(Run.class);
    private Proteu proteu = null;
    private ScriptRunner scriptRunner = null;
    /**
     * Run file.
     * @param proteu Proteu
     * @param file File to be executed
     */
    public Run(Proteu proteu, String file) throws ProteuException {
        this.proteu = proteu;
        scriptRunner = proteu.getScriptRunner();
        logger.info("Running "+ file);
        run(file);
    }
    private synchronized void run(String file) throws ProteuException {
        try {
            String scriptPath = ScriptRunner.searchFile(file);
            if (scriptPath != null) {
            	loadConfig(new File(file).getParentFile());
                if (Cache.check(proteu, file)) {
                    return;
                }
                proteu.getScript().runFile(scriptPath);
                logger.info("Script "+ scriptPath +" executed with success");
            } else {
                loadConfig(new File(Config.getPublic()));
                if (Cache.check(proteu, file)) {
                    return;
                }
                @SuppressWarnings("rawtypes")
				Class aClass = null;
                String classPath = "";
                if (new File(file).exists()) {
                    File dirPublic = new File(Config.getPublic());
                    File dirBuild = new File(Config.getBuild());
                    ClassLoader loader = new URLClassLoader(new URL[] { dirPublic.toURI().toURL(), dirBuild.toURI().toURL() });
                    classPath = file.replace('/', '.');
                    aClass = loader.loadClass(classPath);
                    dirPublic = null;
                    dirBuild = null;
                    loader = null;
                } else {
                    classPath = file.substring(1).replace('/', '.');
                    aClass = Class.forName(classPath);
                }
                Object objectParameters[] = { proteu };
                @SuppressWarnings("rawtypes")
				Class classParameters[] = { objectParameters[0].getClass() };
                @SuppressWarnings("unchecked")
				Method theMethod = aClass.getDeclaredMethod("proteuMain", classParameters);
                theMethod.invoke(null, objectParameters);
                objectParameters = null;
                classParameters = null;
                theMethod = null;
                aClass = null;
                logger.info("Class "+ classPath +" executed with success");
            }
        } catch (Throwable e) {
            logger.warn("Cannot be executed: "+ file, e);
            throw new ProteuException("Cannot be executed: "+ file, e);
        }
    }
    private void loadConfig(File file) throws ProteuException {
    	if (file == null) {
            return;
    	}
        if (file.isDirectory()) {
            String configPath = ScriptRunner.searchFile(file.toString().replace((CharSequence)Config.getBuild(), (CharSequence)Config.getPublic()) + (file.toString().endsWith(File.separator) ? "" : File.separator) + "config");
            if (configPath != null) {
                try {
                    int threadID = Integer.parseInt(proteu.getConfig().getString("thread_id"));
                    scriptRunner.getBindings().put("proteu", proteu);
                    scriptRunner.runFile(configPath);
                    proteu.getConfig().set("thread_id", ""+ threadID);
                    logger.info("Config "+ configPath +" loaded");
                    return;
                } catch (Exception e) {
                    logger.error("Load config: "+ configPath, e);
                    throw new ProteuException("Load config: "+ configPath, e);
                }
            } else {
                if (file.getAbsolutePath().equals(new File(Config.getBuild()).getAbsolutePath())) {
                    return;
                }
                loadConfig(file.getParentFile());
            }
        }
        return;
    }
    @Override
    protected void finalize() throws Throwable {
        proteu = null;
    }
}
